package com.imut.lagain.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imut.lagain.entity.DataOperationLog;
import com.imut.lagain.repository.DataOperationLogRepository;
import com.imut.lagain.service.IDataOperationLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 数据操作日志服务实现类
 * 提供数据操作日志的业务逻辑处理
 */
@Service
@RequiredArgsConstructor
@Transactional
public class DataOperationLogServiceImpl extends ServiceImpl<DataOperationLogRepository, DataOperationLog> implements IDataOperationLogService {
    private static final Logger log = LoggerFactory.getLogger(DataOperationLogServiceImpl.class);

    
    
    /**
     * 记录数据操作日志
     * @param userId 用户ID
     * @param operationType 操作类型
     * @param tableName 表名
     * @param recordId 记录ID
     * @param oldData 旧数据
     * @param newData 新数据
     * @param description 描述
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 创建的日志
     */
    public DataOperationLog logOperation(Long userId, String operationType, String tableName, 
                                       Long recordId, String oldData, String newData, 
                                       String description, String ipAddress, String userAgent) {
        if (!StringUtils.hasText(operationType) || !StringUtils.hasText(tableName)) {
            return null;
        }
        
        DataOperationLog operationLog = new DataOperationLog();
        operationLog.setUserId(userId);
        operationLog.setOperationType(operationType);
        operationLog.setTableName(tableName);
        operationLog.setRecordId(recordId);
        operationLog.setOldData(oldData);
        operationLog.setNewData(newData);
        operationLog.setDescription(description);
        operationLog.setIpAddress(ipAddress);
        operationLog.setUserAgent(userAgent);
        operationLog.setOperationTime(LocalDateTime.now());
        operationLog.setCreateTime(LocalDateTime.now());
        
        boolean saved = this.save(operationLog);
        if (saved) {
            log.info("Logged operation: {} on table {} by user {}", operationType, tableName, userId);
            return operationLog;
        } else {
            log.error("Failed to log operation: {} on table {}", operationType, tableName);
            return null;
        }
    }
    
    /**
     * 记录数据操作日志（简化版本）
     * @param userId 用户ID
     * @param operationType 操作类型
     * @param tableName 表名
     * @param recordId 记录ID
     * @param ipAddress IP地址
     * @param oldData 旧数据
     * @param newData 新数据
     * @return 创建的日志
     */
    public DataOperationLog logOperation(Long userId, String operationType, String tableName, 
                                       Long recordId, String ipAddress, String oldData, String newData) {
        if (!StringUtils.hasText(operationType) || !StringUtils.hasText(tableName)) {
            return null;
        }
        
        DataOperationLog operationLog = new DataOperationLog();
        operationLog.setUserId(userId);
        operationLog.setOperationType(operationType);
        operationLog.setTableName(tableName);
        operationLog.setRecordId(recordId);
        operationLog.setOldData(oldData);
        operationLog.setNewData(newData);
        operationLog.setDescription(operationType + " operation on " + tableName);
        operationLog.setIpAddress(ipAddress);
        operationLog.setUserAgent(null); // 可以从HttpServletRequest中获取，这里暂时设为null
        operationLog.setOperationTime(LocalDateTime.now());
        operationLog.setCreateTime(LocalDateTime.now());
        
        boolean saved = this.save(operationLog);
        if (saved) {
            log.info("Logged operation: {} on table {} by user {}", operationType, tableName, userId);
            return operationLog;
        } else {
            log.error("Failed to log operation: {} on table {}", operationType, tableName);
            return null;
        }
    }
    
    /**
     * 根据用户ID分页查询操作日志
     * @param userId 用户ID
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByUserId(Long userId, Page<DataOperationLog> page) {
        if (userId == null) {
            return new Page<>();
        }
        return baseMapper.findByUserIdWithPage(userId, page);
    }
    
    /**
     * 根据操作类型分页查询
     * @param operationType 操作类型
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByOperationType(String operationType, Page<DataOperationLog> page) {
        if (!StringUtils.hasText(operationType)) {
            return new Page<>();
        }
        return baseMapper.findByOperationTypeWithPage(operationType, page);
    }
    
    /**
     * 根据表名分页查询
     * @param tableName 表名
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByTableName(String tableName, Page<DataOperationLog> page) {
        if (!StringUtils.hasText(tableName)) {
            return new Page<>();
        }
        return baseMapper.findByTableNameWithPage(tableName, page);
    }
    
    /**
     * 根据记录ID查询操作日志
     * @param recordId 记录ID
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByRecordId(Long recordId, Page<DataOperationLog> page) {
        if (recordId == null) {
            return new Page<>();
        }
        return baseMapper.findByRecordIdWithPage(recordId, page);
    }
    
    /**
     * 根据IP地址分页查询
     * @param ipAddress IP地址
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByIpAddress(String ipAddress, Page<DataOperationLog> page) {
        if (!StringUtils.hasText(ipAddress)) {
            return new Page<>();
        }
        return baseMapper.findByIpAddressWithPage(ipAddress, page);
    }
    
    /**
     * 根据操作时间范围查询
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Page<DataOperationLog> page) {
        if (startTime == null || endTime == null) {
            return new Page<>();
        }
        return baseMapper.findByOperationTimeBetween(startTime, endTime, page);
    }
    
    /**
     * 根据描述模糊查询
     * @param description 描述关键字
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> searchLogsByDescription(String description, Page<DataOperationLog> page) {
        if (!StringUtils.hasText(description)) {
            return new Page<>();
        }
        return baseMapper.findByDescriptionLike(description, page);
    }
    
    /**
     * 统计操作次数
     * @param userId 用户ID（null表示所有用户）
     * @param operationType 操作类型（null表示所有类型）
     * @param tableName 表名（null表示所有表）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 操作次数
     */
    @Transactional(readOnly = true)
    public Long countOperations(Long userId, String operationType, String tableName, LocalDateTime startTime, LocalDateTime endTime) {
        QueryWrapper<DataOperationLog> wrapper = new QueryWrapper<>();
        if (userId != null) {
            wrapper.eq("user_id", userId);
        }
        if (StringUtils.hasText(operationType)) {
            wrapper.eq("operation_type", operationType);
        }
        if (StringUtils.hasText(tableName)) {
            wrapper.eq("table_name", tableName);
        }
        if (startTime != null) {
            wrapper.ge("operation_time", startTime);
        }
        if (endTime != null) {
            wrapper.le("operation_time", endTime);
        }
        return baseMapper.selectCount(wrapper);
    }
    
    /**
     * 统计各操作类型的数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 操作类型统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByOperationType(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.countByOperationType(startTime, endTime);
    }
    
    /**
     * 统计各表的操作数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 表操作统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByTableName(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.countByTableName(startTime, endTime);
    }
    
    /**
     * 统计各用户的操作数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 用户操作统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByUserId(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.countByUserId(startTime, endTime);
    }
    
    /**
     * 获取最近的操作日志
     * @param limit 限制数量
     * @return 最近的操作日志列表
     */
    @Transactional(readOnly = true)
    public List<DataOperationLog> getRecentLogs(Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        Page<DataOperationLog> page = new Page<>(1, limit);
        return baseMapper.findByOperationTimeBetween(null, null, page).getRecords();
    }
    
    /**
     * 根据用户ID和表名查询操作日志
     * @param userId 用户ID
     * @param tableName 表名
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByUserIdAndTableName(Long userId, String tableName, Page<DataOperationLog> page) {
        if (userId == null || !StringUtils.hasText(tableName)) {
            return new Page<>();
        }
        return baseMapper.findByUserIdAndTableName(userId, tableName, page);
    }
    
    /**
     * 根据用户ID和操作类型查询操作日志
     * @param userId 用户ID
     * @param operationType 操作类型
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByUserIdAndOperationType(Long userId, String operationType, Page<DataOperationLog> page) {
        if (userId == null || !StringUtils.hasText(operationType)) {
            return new Page<>();
        }
        return baseMapper.findByUserIdAndOperationType(userId, operationType, page);
    }
    
    /**
     * 根据表名和操作类型查询操作日志
     * @param tableName 表名
     * @param operationType 操作类型
     * @param page 分页参数
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<DataOperationLog> getLogsByTableNameAndOperationType(String tableName, String operationType, Page<DataOperationLog> page) {
        if (!StringUtils.hasText(tableName) || !StringUtils.hasText(operationType)) {
            return new Page<>();
        }
        return baseMapper.findByTableNameAndOperationType(tableName, operationType, page);
    }
    
    /**
     * 清理过期日志
     * @param beforeTime 清理此时间之前的日志
     * @return 清理的日志数量
     */
    public int cleanupOldLogs(LocalDateTime beforeTime) {
        if (beforeTime == null) {
            return 0;
        }
        int count = baseMapper.deleteByOperationTimeBefore(beforeTime);
        log.info("Cleaned up {} old operation logs before {}", count, beforeTime);
        return count;
    }
    
    /**
     * 清理过期日志
     * @param days 保留天数
     * @return 清理的记录数
     */
    public int cleanupExpiredLogs(int days) {
        LocalDateTime expireTime = LocalDateTime.now().minusDays(days);
        return cleanupOldLogs(expireTime);
    }
    
    /**
     * 获取表操作统计
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 表操作统计列表
     */
    public List<Map<String, Object>> getTableOperationStats(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getTableOperationStats(startTime, endTime);
    }
    
    /**
     * 获取用户操作统计
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 用户操作统计列表
     */
    public List<Map<String, Object>> getUserOperationStats(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getUserOperationStats(startTime, endTime);
    }
    
    /**
     * 统计指定时间范围内的操作数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 操作数量
     */
    public Long countOperations(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.countOperationsByTimeRange(startTime, endTime);
    }
    
    /**
     * 获取操作类型统计
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 操作类型统计列表
     */
    public List<Map<String, Object>> getOperationTypeStats(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getOperationTypeStats(startTime, endTime);
    }
    
    /**
     * 记录创建操作
     * @param userId 用户ID
     * @param tableName 表名
     * @param recordId 记录ID
     * @param newData 新数据
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 创建的日志
     */
    public DataOperationLog logCreate(Long userId, String tableName, Long recordId, String newData, String ipAddress, String userAgent) {
        return logOperation(userId, "CREATE", tableName, recordId, null, newData, "创建记录", ipAddress, userAgent);
    }
    
    /**
     * 记录更新操作
     * @param userId 用户ID
     * @param tableName 表名
     * @param recordId 记录ID
     * @param oldData 旧数据
     * @param newData 新数据
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 创建的日志
     */
    public DataOperationLog logUpdate(Long userId, String tableName, Long recordId, String oldData, String newData, String ipAddress, String userAgent) {
        return logOperation(userId, "UPDATE", tableName, recordId, oldData, newData, "更新记录", ipAddress, userAgent);
    }
    
    /**
     * 记录删除操作
     * @param userId 用户ID
     * @param tableName 表名
     * @param recordId 记录ID
     * @param oldData 旧数据
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 创建的日志
     */
    public DataOperationLog logDelete(Long userId, String tableName, Long recordId, String oldData, String ipAddress, String userAgent) {
        return logOperation(userId, "DELETE", tableName, recordId, oldData, null, "删除记录", ipAddress, userAgent);
    }
    
    /**
     * 记录查询操作
     * @param userId 用户ID
     * @param tableName 表名
     * @param description 查询描述
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 创建的日志
     */
    public DataOperationLog logSelect(Long userId, String tableName, String description, String ipAddress, String userAgent) {
        return logOperation(userId, "SELECT", tableName, null, null, null, description, ipAddress, userAgent);
    }
    
    /**
     * 根据多个条件查询操作日志
     * @param userId 用户ID
     * @param operationType 操作类型
     * @param tableName 表名
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param page 页码
     * @param size 每页大小
     * @return 操作日志分页列表
     */
    @Transactional(readOnly = true)
    public Page<DataOperationLog> getLogsByConditions(Long userId, String operationType, String tableName, 
                                                     LocalDateTime startTime, LocalDateTime endTime, 
                                                     int page, int size) {
        Page<DataOperationLog> pageParam = new Page<>(page, size);
        QueryWrapper<DataOperationLog> wrapper = new QueryWrapper<>();
        if (userId != null) {
            wrapper.eq("user_id", userId);
        }
        if (StringUtils.hasText(operationType)) {
            wrapper.eq("operation_type", operationType);
        }
        if (StringUtils.hasText(tableName)) {
            wrapper.eq("table_name", tableName);
        }
        if (startTime != null) {
            wrapper.ge("operation_time", startTime);
        }
        if (endTime != null) {
            wrapper.le("operation_time", endTime);
        }
        wrapper.orderByDesc("operation_time");
        
        return (Page<DataOperationLog>) baseMapper.selectPage(pageParam, wrapper);
    }
}

